package com.ruoyi.rulengine.service.impl;

import com.alibaba.fastjson.JSON;
import com.ruoyi.iotcommon.domain.DeviceDataMessage;
import com.ruoyi.rulengine.domain.*;
import com.ruoyi.rulengine.domain.emun.RuleConstant;
import com.ruoyi.rulengine.evaluator.RuleConditionEvaluator;
import com.ruoyi.rulengine.handler.RuleActionFactory;
import com.ruoyi.rulengine.service.IAsyncRuleEngineService;
import com.ruoyi.rulengine.service.IRuleLogService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

// 参考：https://blog.csdn.net/qq_35485206/article/details/145789107
@Slf4j
@Service("ruleEngineService")
public class AsyncRuleEngineServiceImpl implements IAsyncRuleEngineService {

    @Resource
    ThreadPoolTaskExecutor taskExecutor;

    @Resource
    RuleConditionEvaluator evaluator;

    @Resource
    RuleActionFactory ruleActionFactory;

    @Resource
    IRuleLogService ruleLogService;


    public void evaluateRulesAsync(List<Rule> rules, DeviceDataMessage deviceData) {
        List<CompletableFuture<Void>> futures = rules.stream()
                .map(rule -> evaluateConditionsAsync(rule.getConditions(), rule.getLogical(), deviceData)
                        .thenAcceptAsync(isMatched -> {
                            if (isMatched) {
                                // 生成告警日志
                                RuleLog ruleLog = createRuleLog(rule, deviceData, "SUCCESS");
                                // 异步执行动作
                                executeActions(rule.getActions(), deviceData, ruleLog);
                                // 异步插入数据库
                                ruleLogService.saveRuleLog(ruleLog);
                            }
                        }, taskExecutor))
                .toList();

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
    }


    public CompletableFuture<Boolean> evaluateConditionsAsync(List<RuleCondition> conditions, String logic, DeviceDataMessage deviceData) {
        // 异步执行并收集所有条件的满足结果
        List<CompletableFuture<Boolean>> futures = conditions.stream()
                .map(condition -> CompletableFuture.supplyAsync(() -> evaluator.evaluate(condition, deviceData), taskExecutor))
                .toList();

        return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                .thenApply(v -> {
                    // 取出执行判断结果
                    List<Boolean> results = futures.stream()
                            .map(CompletableFuture::join)
                            .toList();
                    log.info(JSON.toJSONString(results));
                    if (RuleConstant.LOGIC_AND.equals(logic)) {
                        log.info("条件同时满足");
                        // 结果都是true,同时满足条件
                        return results.stream().allMatch(Boolean::booleanValue);
                    } else if (RuleConstant.LOGIC_OR.equals(logic)) {
                        log.info("条件任意满足");
                        // 有一个是true，任意满足条件
                        return results.stream().anyMatch(Boolean::booleanValue);
                    } else {
                        throw new IllegalArgumentException("不支持的条件逻辑: " + logic);
                    }
                });
    }


    @Override
    public void executeActions(List<RuleAction> actions, DeviceDataMessage deviceData, RuleLog ruleLog) {
        Map<String, String> actionResults = new HashMap<>();
        CompletableFuture<?>[] futures = actions.stream()
                .map(action -> CompletableFuture.runAsync(() -> {
                    try {
                        // 执行动作，并获取执行结果
                        ActionResult result = ruleActionFactory.getHandler(action.getType()).execute(action);
                        log.info("执行动作: " + action.getType());
                        actionResults.put(action.getType(),  result.getResultDes()); // 记录执行结果
                    } catch (Exception e) {
                        actionResults.put(action.getType(),  e.getMessage()); // 记录失败
                    }
                }, taskExecutor))
                .toArray(CompletableFuture[]::new);

        // 等待所有动作执行完成
        CompletableFuture.allOf(futures).join();

        // 将动作执行结果设置到 RuleLog 中
        ruleLog.setActionResult(JSON.toJSONString(actionResults));
        // 根据动作执行结果更新 RuleLog 的状态
        if (actionResults.values().stream().anyMatch(result -> result.startsWith(RuleConstant.ACTION_FAIL))) {
            ruleLog.setActionStatus(RuleConstant.ACTION_FAIL);
        } else {
            ruleLog.setActionStatus(RuleConstant.ACTION_SUCCESS);
        }
    }

    @Override
    public RuleLog createRuleLog(Rule rule, DeviceDataMessage deviceData, String status) {
        return RuleLog.builder()
                .ruleId(rule.getId())
                .ruleName(rule.getName())
                .level(rule.getLevel())
                .createTime(new Date())
                .productKey(deviceData.getProductKey())
                .deviceKey(deviceData.getDeviceKey())
                .channelKey(deviceData.getChannelKey())
                .actionStatus(status)
                .build();
    }
}
